Hello, I wanted to change the search box appearance from an ugly grey button to some custom image and I found this task being far from trivial (I even think that there is a bug in Drupal Forms API but I'm a total newbie so I don't want to make quick conclusions). If you have the same issue, read on.
First, please forget the technique which uses CSS only. You may hear of an image replacement trick which substitutes textual 'input type=submit' by some image. Forget it - you will never achieve cross-browser compatibility, I tried hard but failed (I published some results on my Czech blog - you won't understand much but you might appreciate code samples).
The right approach is to change the page rendering and to emit 'input type=image' instead of 'input type=submit'. Here's step-by-step guide:
- Navigate to your theme directory and open the template.php file (create it if it doesn't exist).
- Add this function:
function phptemplate_search_theme_form($form) { $form['submit']['#theme'] = 'button'; $form['submit']['#button_type'] = 'image'; $form['submit']['#attributes'] = array( 'src' => '/path-to-your-theme/img/search-button.png', 'alt' => t(Search) ); return form_render($form); }This function changes the search form tree (see the Forms API Quick Start Guide if you don't know what I'm talking about) and then renders the form.
- In the perfect world, this would be enough, but currently, you need to hack into the Drupal code because the Forms API doesn't support 'input type=image' directly. So in template.php, create another function with the following content:
function phptemplate_button($element) { // following lines are copied directly from form.inc core file: //Make sure not to overwrite classes if (isset($element['#attributes']['class'])) { $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class']; } else { $element['#attributes']['class'] = 'form-'. $element['#button_type']; } // here the novelty begins: check if #button_type is normal submit button or image button $return_string = '<input '; if ($element['#button_type'] == 'image') { $return_string .= 'type="image" '; } else { $return_string .= 'type="submit" '; } $return_string .= (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ') .'value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";; return $return_string; } - Now, you should be ready to go!
My opinion is that Forms API should be image-input-type aware by default. Note that I'm a total newcomer so I might overlook some simpler way to do this but searching for "image" inside form.inc gives me some self-confidence :)
Hope this helped.
Comments
Very useful. I was about to
Very useful. I was about to dig in and do the same but you saved me some time, thanks!
One note -- if you're trying to replace the 'search' button in the side block as I was, you want to implement
function phptemplate_search_block_form($form)rather than the function you have in the first block of code above.In Drupal 4.7 this causes drupal to fail to be able to post
Implimented this solution and had a custom search button image which seemd like all was well but then found I could no longer post any data for new pages or edit existing pages. When page is submitted nothing happens but the search does work . :-(
Any ideas???
Jeffrey Dalton
Creative Director & Founding Partner
BKJ Digital
https://bkjdigital.com
Better to use a module
Better to use a module according to this post...
http://drupal.org/node/140387.
It may be related to the problem you're having and it also may be related to this entire post which goes in the direction of editing the form button via a function at the theming level. The user mooffie states that theming functions are run after forms are processed.
Good luck!
Exactly what I needed. Thanks.
Exactly what I wanted to achieve and I was half-way there in a similar fashion till I came across your much neater #button_type work-around.
I agree that this is the "right" way to work around what feels like and oversight in core. Much better than CSS hacks.
Thanks for posting.
Extra submit button
Thanks for this. I've almost got it working, but I'm getting two buttons in the code, the new graphic one and the old grey one. FWIW they both work. What am I missing?
I'm doing this to a webform if that makes a difference.
Use the right element name
If the form you're altering uses a different name than "submit" for its submit button, then declaring "$form['submit'][...]" will add an element instead of altering the details of the existing one.
Just change 'submit' to whatever your submit button is called. If you're using the name automatically generated by the webform module, this could be something like "submit_NNNNNNNNNN", where NNNNNNNNNN is a timestamp like '1174926303' or similar. IIRC this should be visible on the webform editing page for the form. Failing that you could look at the HTML code for the finished page and find the "name" the original submit button was given.
Hope that helps. Good luck!
++Andy
Drupal 5.x fix
This works fine in my 5.0 installation after addressing one minor change - form_render has been deprecated (in the sense of 'removed') in favour of drupal_render (as mentioned here: http://drupal.org/node/107459).
So the phptemplate_search_theme_form function I have in my template.php file right now is as follows:
++Andy
Code addition to fix edit issue
When overriding the button function I was no longer able to expand any of the fieldsets of options for a node when in edit mode (at least in 5.x). The issue is that the overridden buttons are missing the id attribute which is required by the drupal/upload javascript files for the upload button (attach-button). Minor addition below (added the id attribute) fixed it.
PS Thanks for the original code Borek!
This can be dropped down even further...
I found the same problem, but resolved it very simply by adding another condition to replace the "submit" as below. This is using drupal 5.1 and fckeditor 2.4. Thanks for the original code though. Lifesaver.
Shortest phptemplate_button yet!
Brilliant. Thanks for that: it saved our bacon during a pair-programming session.
Any reason why the core function we're stubbing out doesn't use the
.=operator on the classes? Like this:Also, here's a version of the
hook_alter_formto use if you prefer that to intercepting the form at the template level rather than usingphptemplate_search_theme_form:Expand that
if ()withelsestatements for whatever you fancy overriding.--
J-P Stacey, software gardener, Magnetic Phield
I"ve tried this. To see if
I"ve tried this. To see if I'm getting hooked, I echo some things and it's getting run.
But, my HTML for the search submit btn isn't including the img src bit. I've verified my path to the image.
Is there anything else people can elaborate on which may fix?
Thanks,
Adam
Explorer 7 problem
I tried this code to modify my poll block vote button
the result works in firefox but not in explorer 7
Thanks
form_render() Not Found
I added both of the noted functions to template.php, but I recevie an error message saying the form_render() is undefined. Any thoughts?
Thanks,
Andrew
yea...look at the above comment
http://drupal.org/node/62647#comment-214956 I got it to work after i changed the function name.
Parse error
Parse error: parse error, unexpected T_VARIABLE in the line
$form['submit']['#theme'] = 'button';
I tried also with another name instead of 'submit' but the same problem...
Why? (sorry! no idea of PHP but a master on copy-paste ...)
I have Druapl 5.1
psc
Since that line looks OK to
Since that line looks OK to me, it's possible the problem really lies on the preceding line - it's not expecting to encounter that variable because it's not done with whatever it was doing before.
Check the end of the line before - did the '{' fall off somehow? (Or, if you've added code, did you miss a ';' ?)
++Andy
...but error persists
I copied the two fixes functions for Drupal 5. Yours and tklawsuc's.
The one and only chage I did is the name of the search button image file in my theme images folder.
Is there anything else I should change?
My error message:
Parse error: parse error, unexpected T_VARIABLE in /homepages/24/d32156390/htdocs/drupal5/sites/all/themes/mytheme/template.php on line 31
Line 31 in my template.php is
$form['enviar']['#theme'] = 'button';
Thanks!
psc
Again, though it's
Again, though it's encountering the unexpected variable on line 31 it's likely due to a typo on an earlier line (it's one of those subtly misleading, though wholly accurate, error messages) ... if you post the whole function I'll see if I can spot anything obviously out of place.
++Andy
the function
function phptemplate_search_theme_form($form) {
$form['submit']['#theme'] = 'button';
$form['submit']['#button_type'] = 'image';
$form['submit']['#attributes'] = array(
'src' => base_path() . path_to_theme() . '/images/mysearch.png',
'alt' => t(Search)
);
return drupal_render($form);
}
if i change 'submit' with something different, i get the same error...
should I change something on it (apart form changing my search icon name)?
psc
Try : 'alt' => t('Search')
Try : 'alt' => t('Search')
Added to theme snippets library
Hope you all don;t mind but I found this so incredibly useful that I added it to the snippets library so others would be more readily able to find it and make use of it:
http://drupal.org/node/144758
Sean Robertson
webolutionary@webolutionary.com
Sean Robertson | @seanr1978 on twitter
seanr@webolutionary.com
thanks
This is a great snippet.
Agree, this functionality should be in core.
Thanks also to kingandy's comment.
Ugly but much less code
I did this instead on the output form returned,
much easier, even though I have to admit it is a shortcut and I don't know about the efficiency when there's a lot of users...
Anyone achieve to make this
Anyone achieve to make this work in IE? After pressing the submit image button, it didn´t work in this explorer (it only returns to the same comment page). Any idea? Thanks in advance, Simon.
So I must say that this
So I must say that this method don´t work in drupal 5.1. At least, for me.
responded in your other thread
hi simon,
i think i've found out what the issue is in IE
responded in your other thread:
http://drupal.org/node/160682
CSS can get you there, too...
I wanted to do the same for one of our sites recently and realized the non-trivial size of the task as well. I decided to handle this on the completely other end (via CSS) - but I do wish I'd seen this thread first.
Big picture - both the search text field and the search button needed to be styled. The text field had an odd background (rounded corners and a slight gradient). The search button was a magnifying glass (or some such thing). The following CSS accomplished it in Win IE6, IE7, Firefox 2 and Mac Firefox 2 and Mac Safari 3 (currently in beta). Mac Safari 2 doesn't allow real styling of buttons, but as our site is under development and Safari 3 solves it, we're considering this a sufficient solution (and I like anything that can keep us from fiddling with php - better upgrade paths, etc.)
So - here's the CSS I put together:
Took some fiddling to get there, but it works... and it's a pure CSS solution - which means your php can remain untouched.
Drew Gorton
Gorton Studios
Some of our Drupal Sites
I personally had problems in
I personally had problems in opera with the above code, although it worked fine in every other major browser,
however, I am currently using a solution detailed on the below link, and it seems to work for me on every major browser.
http://www.ampsoft.net/webdesign-l/image-button.html
Accessibility issues
I remember reading an article somewhere that pointed out those methods will make the page unreadable if you have CSS enabled but don't load images for some reason (either a temporary connection glitch or if you just have images disabled as a matter of course - maybe to conserve bandwidth or some such). Since it's not an actual image object you don't get the luxury of 'Alt' text, so if the background image fails to load for whatever reason you'll just get a blank area.
The article did propose some method of addressing it, but I can't remember what. Possibly placing the image in a separate block area, absolutely positioned so as to appear in front of the text? That technique probably wouldn't be applicable for a Submit button anyway.
That said, I use this method all the time for headers. I just thought it was worth mentioning for those of us who care more than me ;)
--Andy
Developing Drupal websites for Livelink New Media
++Andy
Hmm, thats a great point.
Hmm, thats a great point. The problem would also effect to text based browsers, and accessibility to the disabled (such as blind). Not sure if a PA fix is really the idea solution. Plus it may become a little complicated if you start moving stuff around with javascript (such as moofx).
If anyone has ideas on a good solution, please enlighten me. I will look into this myself, if I figure anything else i'll post it up here.
Thanks!
Richard Box
Yes...
Like Andy, I'm both aware of this issue and also aware of my own failings.
FWIW, you can scrutinize that code in it's real life form at http://www.greenguardian.com/. Having a real life test URL may help any effort to throw lots of different user agents at the code and find it's shortcomings.
Suggestions for further improvements are always welcome!
Drew Gorton
Gorton Studios
For what it's worth...
FWIW, most text-based browsers and/or readers won't be impacted by a text-indent declaration - likewise the normal document flow returns if CSS is lost altogether. It's only people in the bizarre twilight hinterland of active-CSS-but-no-images that will be affected.
--Andy
Developing Drupal websites for Livelink New Media
++Andy
Accessible CSS form buttons
In case anyone reads this down the line... I found this solution which works great and solves the above-mentioned accessibility concerns:
http://fortysevenmedia.com/blog/archives/making_accessible_css_buttons_l...
-- David
davidnewkerk.com | absolutecross.com
View my Drupal lessons & guides
Code causes problems with collapsible fieldsets
Half a year later, I realise that this is what has caused my collapsible fieldsets to conflict with the inline upload functionality. Comparing it with the core theme_button() function, I've realised this code is neglecting to declare an id attribute in the returned input tag. The following code seems to function correctly:
--Andy
Developing Drupal websites for Livelink New Media
++Andy
Which is why CSS is nice...
This is a great case-in-point where PHP changes can cause something unintended, and a reason to consider spending the time to solve these sorts of visual changes through CSS alone wherever possible. It can still break, mind you (if, for example, the HTML output, such as IDs change) - but that sort of break is both quickly obvious (it's visual) as well as extremely unlikely to effect the functionality of anything else (e.g. only if something else where to be output with ' id="search" ').
Not trying to take away from the hard work and usefulness of the above solutions - just been through this sort of ringer before and unhappy with having to go back and fiddle with phptemplate_* functions when oddities such as this are discovered.
Drew Gorton
Gorton Studios
Proper use of Themeable functions
The other thing that occurred to me while investigating this was that completely overriding the function - ie, duplicating it and making your own changes - means any changes in the core function down the line will not be reflected (which is in fact what's happened here - the 4.7 version of the function doesn't include the id attribute).
Perhaps a better function would be something like:
... Or, heck, even simpler:
... since literally all we're doing is changing the type from "submit" to "image" (all the SRC attributes and such get passed through regardless of the element type.
On a final note I've noticed this comment above by tklawsuc which both identified and resolved the problem about a week after my first post in this thread. I am dumb.
--Andy
Developing Drupal websites for Livelink New Media
++Andy
This requires no changes to elements and allows for l10n
Here's a version that looks for images based on the button's #value. This means it will display an image only if the theme has one, but not otherwise (i.e. if 'Submit' was translated to another language).
In this case the theme is called medemcom and images are in themes/medemcom/i/.
Awesome!
@Dave Cohen
What a great piece of code, while I can see the advantage of using css to do this...was the original direction I was going in, the ability to just create a button say from my own button "dev kit", and then name it like so...drop it in, and forget it...awwww yeah!
thanks!
You know what, unfortunately
You know what, unfortunately I started to have problems with that code. Damn IE can't cope with image buttons like normal browsers do. So for example if you make all your Submit buttons images, then on IE you'll have trouble submitting nodes.
If you have any tips to solve that please post here.
Why not just use CSS?
Won't it get you there faster and more reliably? The code in the comment above (http://drupal.org/node/62647#comment-258485) works just fine (you can see it in the wild at http://www.greenguardian.com). Variations on that code exist on most of our sites and it works well. Arguably, the CSS above was a bit dense with the layering of background images and all - but a simpler version can be seen, for example, on the Rake Magazine -- http://www.rakemag.com -- just hit the search button with Firebug to take a look:
No fussing about with phptemplate functions, no worries with upgrade paths or unintended consequences - that code is only going to effect the search box - and it will do so in a way that degrades extremely well. I have trouble seeing the downside, I guess.
Regardless, however, the good news is that this will be an obsolete conversation come Drupal 6 - I recall reading a changelog somewhere (* I think *) describing image submit buttons in core.
Drew Gorton
Gorton Studios
what version of IE?
I've got this running on two sites that work well under the following
IE6
IE7
FF2
Opera9
Safari (3.0.4/win)
I have however, not replaced any of drupal's "admin" buttons, but then again, I also use an admin theme anyway.
but I've replaced:
search
advanced search
post comment
preview comment
Log In
Create New Account
and a few others...
what kind of IE issues and where did you encounter them ?
When a button is an image on
When a button is an image on IE, it neglects to POST the button's value. For many forms this works OK. For the node submit form, Drupal needs to know whether the button pressed was Submit as opposed to Preview or Delete. Since IE never tells the server it was the submit button, nodes can no longer be submitted.
@dgorton: I used code rather than stylesheets because I wanted to very easily support a bunch of different buttons which appear on different forms. In my case the images are pictures of words, and I wanted the proper image to be found on translated pages (and fail gracefully if the translated image was not found).
An (ugly) solution
I just posted one here: http://drupal.org/node/153902#comment-751457
It works for the edit form, but it does require functional jQuery in IE.
also, meant to add to this...
in order to handle buttons like "Log In" or "Advanced Search" etc, add str_replace() to remove the space in between words.
change this:
to:
again...great snipplet!
Just use CSS
This is a presentation-layer problem, so solve it in the presentation layer -- leave your markup and php and modules and API's alone :)
I think you're right:
I think you're right: between these two hacks, the CSS option is the least evil.
FWIW, however, I had better luck with the second technique presented at http://www.ampsoft.net/webdesign-l/image-button.html (the above code failed due to the font-size being set to 0pt):
This one works well
Thanks this one works great.
All I changed was to add the search ID in front of #edit-submit so that my admin forms (and other onsite form submit buttons) didn't change to a little search graphic.
Thanks cooperwd, I feel this
Thanks cooperwd,
I feel this is the best method-- changing the font size to 0px. Other methods mentioned in this page change the padding settings and hide the overflow content, which distorts the placement of the searchbutton in my theme. This one, changing the font-size to 0 is cool, works without distorting my theme alignments.
Loving Life,
Tosho Freny,
Great thanks
Works great thanks!
*****************************
Drupal Video Tutorials (Spanish)
www.drupalcarmen.com
coodrup, Good idea to use
coodrup,
Good idea to use font-size: 0; to get rid of the "send" or "submit" text.
Thanks for that.
Using theme override and javascript
My earlier approach had the shortcoming that on IE the value of the button was not submitted, and drupal failed to learn the $op of many form submits. (The shortcoming is in IE, not the technique itself). To work around IE's lameness, I'm now using a combination of themeing and javascript. Images are used in place of buttons only when javascript is enabled, and the theme function finds an image for the button in question.
First, the theme function renders both a button and an image. The image is set not to display:
My theme includes some javascript on every page, and that javascript does two things. First, it hides the buttons and shows the images in their place. Second, when an image is clicked, it triggers the click event on the button. That way its as if the button was pressed, not the image, thus despite the efforts of the developers in Redmond, IE is bent to obey our will:
@Dave
@Dave
Thanks for this code, it's a big help.
I did notice some strange behavior (in IE of course) on certain forms (specifically the pollfield module), where the form was being submit twice. It seems like the click() function is actually being handled differently on IE vs FF/Safari, so I modified the jQuery:
This method might also need a bit of testing to make sure that the direct parent form is being submit, but other than that, I think this should work.
Anyone see any other problems with my changes?
[Update]
Testing indeed... the above bit of jQuery is rubbish. Well, it worked for the pollfield submission form, but seemed to break just about every other form. Needless to say, I would not use it.
[Update Deux]
Ok, I think I've found a solution that works now... Back to Dave's method of emulating the click on the button, with on slight change. I removed (or commented out below) the click() function in the prototype function for the hidden submit button. This second click() was firing a second click event, which broke some forms.
Hmmmmm..... I can't recall
Hmmmmm..... I can't recall exactly which browser or what the circumstances were, but I remember needing that this.click() to get a form to submit properly. And it was this.click() (on the DOM object), not $(this).click() (on the jquery object) that I needed.
Maybe we're using different versions of jquery? I've only used that code in Drupal 5.x.
Thanks for the updates, though. It would be good to be certain that code really works everywhere.
Ahhh... I think you nailed
Ahhh... I think you nailed it, cuz I forgot to mention that I was using a newer version of jquery (1.1.2 from the jquery_update module).
Once again, thanks for posting this in the first place, I now it working on more than 30 or 40 buttons, and can see where this would be very useful for a multi language scenario.
nice - I was looking for something like this - thanks.
gracias.
the php part of this works
the php part of this works great, however, the js is doing nothing. It's been added to the theme template, so it's on all the pages.... any ideas?
running drupal 5x, my site's got jquery updated to 1.2.6 I don't know js well, could the problem be that this code is outdated?
Using Images as Submit
I recommend using this technique instead:
http://alligatorsneeze.com/node/943
Code Positive Limited
Drupal Developers & Consultants - London, UK
------------------------------------------
Drupal Specialists: Consulting, Development & Training
Robert Castelo, CTO
Code Positive
London, United Kingdom
----
robert: thats a great
robert: thats a great method but unfortunately it doesn't address the problem with IE. just tried it today.
submit function
Miriam N.
Hi,
The replacement of the button with an image works perfectly to me,
BUT-
I have a submit function to my form and it hasn't been called! just the "form action" was performed..
What did I missed???
thank you,
Miriam
drupal 6
drupal 6 way:
http://drupal.org/node/316740
Hi, It seems to be working
Hi,
It seems to be working except one thing. For some reasons I end up having two buttons, one is the type of image, the second is type of submit.
How to remove the default one and leave just the new image button in the form?
Thanks,
Dan
Two buttons except just one
Hi,
It seems to be working except one thing. For some reasons I end up having two buttons, one is the type of image, the second is type of submit.
How to remove the default one and leave just the new image button in the form?
Thanks,
Dan
Hi, I found a nice easy way
Hi,
I found a nice easy way was to do it on the form_alter and just use the markup instead:
Thank You!
Thank you for your post peterhh. I can't believe how much time I wasted on this stupid problem.
Found Where The ACTUAL Problem Was
Not sure if this will be the case for everyone, but I found what the core problem was with this issue.
In typical HTML, you can customize a Form Submit Button a few ways. The default would be - type="submit" - followed by the method this thread addresses - type="image" - where you include the source of the image. If you look at the code in - system.module - you'll find where Drupal and developers weren't speaking the same language.
The third $type variable is where the problem is. For image submit buttons, Drupal was expecting me to set the button type to - "'#type' => 'image_button'" - where I was logically expecting to set the button type to - "'#type' => 'image".
So instead of setting my Image Submit Button Input Type to "image," I used "image-button" and all my problems were gone...well...not ALL...but the ones concerning input type image.
I also added the "name" attribute and value to that particularly problematic line of code. See below.
I hope this helps someone else.
Great solution, You don't have to hack the core!
In order to not hack the core you just need to add the button theming as a theme function.
This way:
Solution for image submit button
Hello everybody,
This will solve the issue. I have tried this in Drupal 6.19.
Your image submit button code
Hi,
Where would I insert this code? I am using Drupal 6 with the Genesis template.
Thanks,
Ray
For Drupal 7
This is a solution for Drupal 7. In my case it was to set the login button of the user login block to an image. Essential was to set the array value of #theme_wrappers to 'image_button' and to pass the complete $vars array to the render function otherwise you will have two buttons.
function
And another d7 solution.
changing css
I use css to change the button
first added a div id to identify the button
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Send'),
'#prefix' => '
'#suffix' => '
',
);
then on the css I add the style of the buton
#contact_submit .form-submit{
background:url(images/button-submit.png) no-repeat;
height:34px;
width:129px;
border:none;
text-indent:-9999px;
cursor:pointer;
}
hope this help